﻿using System;
using System.Windows.Input;
using Microsoft.Maps.MapControl.WPF;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows;
using System.Collections.Generic;
using Shrestha.Charts.Commands;
using Shrestha.Data.EventModel;
using System.Data;
using System.Linq;
using System.Collections;

namespace Shrestha.Charts
{
    public class MapWindowViewModel
    {
        private MapWindow _mw;
        private Map _map;
        internal Canvas _selcanvas { get; set; }

        public ICommand ExitCommand { get; set; }
        public ICommand MapSearchCommand { get; set; }
        public ICommand MapUndoCommand { get; set; }
        public ICommand MapResetCommand { get; set; }
        public ICommand SelectCommand { get; set; }

        public bool IsSelected { get; set; }
        
        private Location _sl1, _sl2, _sl3, _sl4;
        private Point _selDown;
        private MapLayer _selectionLayer;
        private bool _isTracking;
        private MapPolygon _selectionPolygon;

        private Rectangle _selrect;
        //private TriEventCollection _teCollection;

        public string Condition { get; set; }
        private DataView _dv;
        private readonly Runner _r;
        private MapLayer mLayer;

        private int _currentzoom;
        ControlTemplate template;

        private const double zoomToLocationRatio = 0.3;

        public MapWindowViewModel(MapWindow mapWindow, Runner r)
        {
            this._mw = mapWindow;
            this._map = _mw.mMap;
            this._selcanvas = _mw.mSelectionCanvas;
            this._r = r;
            InitializeHandlers();
            
            this.MapSearchCommand = new MapSearchCommand(this);
            this.MapUndoCommand = new MapUndoCommand(this);

            this.IsSelected = false;
            this.Condition = "";
            Filter();
        }

        private void InitializeHandlers(){
            _map.MouseDown += new MouseButtonEventHandler(_map_MouseDown);
            _map.MouseUp += new MouseButtonEventHandler(_map_MouseUp);
            _map.MouseMove += new MouseEventHandler(_map_MouseMove);

            _map.Loaded += new RoutedEventHandler(_map_Loaded);

            _selectionPolygon = new MapPolygon()
            {
                Locations = new LocationCollection(),
                Fill = Brushes.LightBlue,
                Stroke = Brushes.Blue,
                StrokeDashArray = { 4, 5 },
                StrokeThickness = 1,
                Opacity = 0.3
            };

            _selectionLayer = new MapLayer();
            _map.Children.Add(_selectionLayer);

            _selrect = new Rectangle()
            {
                Stroke = Brushes.Black,
                StrokeThickness = 1,
                StrokeDashArray = { 4, 5 }
            };
            _selcanvas.Children.Add(_selrect);
        }

        void _map_Loaded(object sender, RoutedEventArgs e)
        {
            
            _map.SetView(new LocationRect(_r.Meta.MinLatitude, _r.Meta.MinLongitude, _r.Meta.MaxLatitude, _r.Meta.MaxLongitude));
        }

        void _map_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsSelected && _isTracking)
            {
                e.Handled = true;
                Point mousePos = e.GetPosition(_map);

                Canvas.SetLeft(_selrect, _selDown.X < mousePos.X ? _selDown.X : mousePos.X);
                _selrect.Width = Math.Abs(mousePos.X - _selDown.X);

                Canvas.SetTop(_selrect, _selDown.Y < mousePos.Y ? _selDown.Y : mousePos.Y);
                _selrect.Height = Math.Abs(mousePos.Y - _selDown.Y);
            }
        }

        void _map_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (IsSelected)
            {
                e.Handled = true;
                _sl3 = _map.ViewportPointToLocation(e.GetPosition(_map));

                _sl2.Longitude = _sl3.Longitude;
                _sl4.Latitude = _sl3.Latitude;

                _selectionPolygon.Locations.Add(_sl1);
                _selectionPolygon.Locations.Add(_sl2);
                _selectionPolygon.Locations.Add(_sl3);
                _selectionPolygon.Locations.Add(_sl4);

                _selectionLayer.Children.Add(_selectionPolygon);
                _isTracking = false;

                Mouse.OverrideCursor = null;
                _selrect.Visibility = Visibility.Collapsed;

                _map.Children.Remove(mLayer);
                Draw();

                LocationRect lr = new LocationRect(_selectionPolygon.Locations);
                _map.SetView(lr);
                

            }
        }

        void _map_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (IsSelected)
            {
                Mouse.OverrideCursor = Cursors.Cross;
                _isTracking = e.Handled = true;
                _selectionLayer.Children.Clear();
                _selectionPolygon.Locations.Clear();
                _selDown = e.GetPosition(_map);
                _sl1 = _map.ViewportPointToLocation(_selDown);

                _sl2 = new Location();
                _sl2.Latitude = _sl1.Latitude;

                _sl4 = new Location();
                _sl4.Longitude = _sl1.Longitude;
            }
        }


        public void Draw()
        {
            if (_dv == null) return;

            mLayer = new MapLayer();

            double val = 0.0001;

            MapPolygon mp;
            int temp;

            foreach (DataRow dr in _dv.ToTable().Rows)
            {
                temp = int.Parse(dr[_r.GradientName].ToString());
                val = GetSize(temp);
                mp = new MapPolygon()
                    {
                        Locations = new LocationCollection()
                        {
                            new Location((double)dr[_r.LatName] - val, (double)dr[_r.LngName] -val),
                            new Location((double)dr[_r.LatName] - val, (double)dr[_r.LngName] + val),
                            new Location((double)dr[_r.LatName] + val, (double)dr[_r.LngName] + val),
                            new Location((double)dr[_r.LatName] + val, (double)dr[_r.LngName]-val)
                        },
                        Stroke = Brushes.White,
                        Fill = GetColor(temp),
                        StrokeThickness = 1.0
                    };
                mLayer.Children.Add(mp);
                    //mLayer.Children.Add(new Pushpin() { Location = new Location((double)dr[_r.LatName], (double)dr[_r.LngName]) });
            }

            //int dbzoom;
            //if (_currentzoom < 0)
            //    _currentzoom = dbzoom = _map.ZoomLevel > 9 ? (int)Math.Floor(_map.ZoomLevel * zoomToLocationRatio) : 0;
            //else
            //    dbzoom = _currentzoom;

            //var gd = from b in _dv.ToTable().AsEnumerable()
            //         group b by new
            //         {
            //             xLat = Math.Round(b.Field<double>("Latitude"), dbzoom),
            //             xLng = Math.Round(b.Field<double>("Longitude"), dbzoom),
            //         }
            //             into g
            //             select new
            //             {
            //                 gLocation = new Location(g.ElementAt(0).Field<double>("Latitude"), g.ElementAt(0).Field<double>("Longitude")),
            //                 gSum = g.Count(),
            //                 gLat = g.Key.xLat,
            //                 gLng = g.Key.xLng
            //             };

            //Console.WriteLine(gd.Count());
            //Console.WriteLine(_map.ZoomLevel);

            //foreach (var dr in gd.ToList())
            //{
            //    Pushpin p = new Pushpin() { Location = dr.gLocation };
            //    double[] k = new double[3];
            //    if (dr.gSum > 1)
            //    {
            //        p.Content = dr.gSum;
            //        k[0] = dbzoom;
            //        k[1] = dr.gLat;
            //        k[2] = dr.gLng;
            //        p.Tag  = k;
            //        p.MouseDoubleClick += new MouseButtonEventHandler(p_MouseDoubleClick);
            //        mLayer.Children.Add(p);
            //    }
            //    else
            //    {
            //        mLayer.Children.Add(new Pushpin() { Location = dr.gLocation });
            //    }
            //}

            _map.Children.Add(mLayer);
        }

        private Brush GetColor(int currentval)
        {
            if (currentval < 11) return Brushes.Sienna;
            else if (currentval < 51) return Brushes.RoyalBlue;
            else if (currentval < 101) return Brushes.Orange;
            else return Brushes.Red;
        }

        private double GetSize(int currentval)
        {
            if (currentval < 11) return 0.0001;
            else if (currentval < 51) return 0.0002;
            else if (currentval < 101) return 0.0004;
            else return 0.0005;
        }

        void p_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            FocusIntoPushpin(sender as Pushpin);
        }

        private void FocusIntoPushpin(Pushpin pg)
        {
            //_map.Children.Remove(mLayer);
            //mLayer.Children.Clear();
            //double[] k = pg.Tag as double[];
            //int dbzoom;
            //_currentzoom = dbzoom = (int)k[0] < 14 ? (int)(zoomToLocationRatio * _map.ZoomLevel) : (int)k[0];

            //var gd = from b in _dv.ToTable().AsEnumerable()
            //         where k[1] == Math.Round(b.Field<double>("Latitude"), (int)k[0]) && k[2] == Math.Round(b.Field<double>("Longitude"), (int)k[0])
            //         group b by new
            //         {
            //             xLat = Math.Round(b.Field<double>("Latitude"), dbzoom),
            //             xLng = Math.Round(b.Field<double>("Longitude"), dbzoom),
            //         }
            //             into g
            //             select new
            //             {
            //                 gLocation = new Location(g.ElementAt(0).Field<double>("Latitude"), g.ElementAt(0).Field<double>("Longitude")),
            //                 gSum = g.Count(),
            //                 gLat = g.Key.xLat,
            //                 gLng = g.Key.xLng
            //             };


            //foreach (var dr in gd.ToList())
            //{
            //    Pushpin p = new Pushpin() { Location = dr.gLocation };
            //    if (dr.gSum > 1)
            //    {
            //        p.Content = dr.gSum;
            //        k[0] = dbzoom;
            //        k[1] = dr.gLat;
            //        k[2] = dr.gLng;
            //        p.Tag = k;
            //        p.MouseDoubleClick += new MouseButtonEventHandler(p_MouseDoubleClick);
            //        mLayer.Children.Add(p);
            //    }
            //    else
            //        mLayer.Children.Add(new Pushpin() { Location = dr.gLocation });
            //}
            //_map.Children.Add(mLayer);
        }

        public void FocusOut()
        {
            _currentzoom = 0;
            Draw();
        }

        private void Filter()
        {
            _dv = _r.GetCondition(Condition);
        }

        internal void GoToLocation(Location location)
        {
            Pushpin pin = new Pushpin();
            pin.Location = location;
            _map.SetView(location, 14);
            _map.Children.Add(pin);
        }



        internal void PinSearchResults()
        {
            //if (_locationList.Count < 2)
            //{
            //    _map.Children.Add(new Pushpin() { Location = _locationList[0] });
            //    _map.SetView(_locationList[0], 14);
            //}
            //else
            //{
            //    foreach (Location l in _locationList)
            //    {
            //        _map.Children.Add(new Pushpin() { Location = l });
            //    }
            //    _map.SetView(_locationList, new Thickness(75.0), 0.0);
            //}
        }

        
    }
}
